package controleur;
import java.io.File;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;

import javax.swing.JOptionPane;

import modele.Interface;
import modele.entites.Bot;
import modele.entites.BotAmphibie;
import modele.entites.BotForet;
import modele.entites.BotUrbain;
import modele.entites.EtatMapEntite;
import modele.entites.Feu;
import modele.entites.MapEntite;
import modele.entites.Orientation;
import modele.entites.TypeBot;
import modele.map.Case;
import modele.map.Map;
import modele.simulation.Manager;
import modele.simulation.Statistiques;
import vues.*;
import modele.Astar;
import modele.Couple;

public class Simulateur implements Serializable {
	
	// public
	public static final int COEFFIFICIENT_AXE = 10; // Coefficient donnant la distance d'une case � une autre d�s lors que c'est dans l'axe : verticale ou horizontale
	public static final int COEFFIFICIENT_DIAGONALE = 15; // Coefficient donnant la distance d'une case � une autre d�s lors que c'est dans la diagonale

	// 
	private static final long serialVersionUID = 1L;
	private ArrayList<MapEntite> mapEntites;
	private Map map;
	private Manager manager;
	private IHM ihm;
	private String PathSimulation;
    private String Nomsimulation;
    private String FinalPath;
    private String PathSimulationMere;
    private String TempsSimulation;
	private Statistiques stats;

	
	
	public Simulateur() {
		this.setTempsSimulateur("0");
		this.mapEntites = new ArrayList<>();
		this.manager = new Manager(this);
		this.map = new Map();
	}
	
	public void miseAJour() {
		this.ihm.getPanStats().MiseAJourTempsSimulation();
		this.manager.miseAJour();
		for (MapEntite me : mapEntites) {
			me.miseAJour();
		}
	}
	
	public MapEntite getEntiteFromCase(int X, int Y){
		for(int i = this.getMapEntites().size()-1; i >=0; i --)
			if(this.getMapEntites().get(i).getCaseCourante().getX() == X && this.getMapEntites().get(i).getCaseCourante().getY() == Y)
				return this.getMapEntites().get(i);
		return null;
	}
	
	public void addRobot(TypeBot choix, String nom, int x, int y) {
		switch (choix) {
		case Foret:
			BotForet bf = new BotForet(nom, this.ihm, new Astar());
			bf.setCaseCourante(this.map.getCase(x, y));
			mapEntites.add(bf);
			break;
		case Amphibie:
			BotAmphibie ba = new BotAmphibie(nom, this.ihm, new Astar());
			ba.setCaseCourante(this.map.getCase(x, y));
			mapEntites.add(ba);
			break;
		case Urbain:
			BotUrbain bu = new BotUrbain(nom, this.ihm, new Astar());
			bu.setCaseCourante(this.map.getCase(x, y));
			mapEntites.add(bu);
			break;
		}
	}

	public void addFeu(int x, int y) {
		Feu f = new Feu(Orientation.NORD,2);
		f.setCaseCourante(this.map.getCase(x, y));
		mapEntites.add(f);
	}
	
	public void supprimerRobot(Bot b)
	{
		this.mapEntites.remove(b);
	}

	public ArrayList<MapEntite> getMapEntites() {
		return this.mapEntites;
	}
	
	public void setMapEntites(ArrayList<MapEntite> mapEntites) {
		this.mapEntites = mapEntites;
	}

	public String getPathSimulateur() {
		return PathSimulation;
	}
	
	public void setPathSimulateur(String pathSimulation) {
		PathSimulation = pathSimulation;
	}

	public String getNomSimulateur() {
		return Nomsimulation;
	}
	
	public void setNomSimulateur(String nomsimulation) {
		Nomsimulation = nomsimulation;
	}

	public String getTempsSimulateur() {
		return TempsSimulation;
	}
	
	public void setTempsSimulateur(String tempsSimulation) {
		TempsSimulation = tempsSimulation;
	}

	public Map getMap() {
		return map;
	}
	
	public void setMap(Map map) {
		this.map = map;
	}

	public String getPathSimulationMere() {
		return PathSimulationMere;
	}

	public void setPathSimulationMere(String pathSimulationMere) {
		PathSimulationMere = pathSimulationMere;
	}

	public Statistiques getStats() {
		return stats;
	}

    public String getFinalPath() {
        return FinalPath;
    }

    public void setFinalPath(String finalPath) {
        FinalPath = finalPath;
    }

	public void setStats(Statistiques stats) {
		this.stats = stats;
	}

	public void save() {
		if(this.getNomSimulateur() == null) {
            this.setNomSimulateur(JOptionPane.showInputDialog(ihm, "Veuillez saisir un nom de simulation", "Nom simulation", JOptionPane.QUESTION_MESSAGE));
        }else{
			//this.setPathSimulateur(getPathSimulateur() + getNomSimulateur()); ??
			this.setPathSimulationMere(getFinalPath());
			if(this.ihm.getPanStats().getValeurTemps() != null && this.getTempsSimulateur() == null)
				this.setTempsSimulateur(this.ihm.getPanStats().getValeurTemps().getText().replace(':', '-'));
			else if(this.getTempsSimulateur() != null){}
            else
				this.setTempsSimulateur("0");
		}
		
		File tr = new File("./","simulations");
        if (!tr.exists())
            tr.mkdirs();
        this.setPathSimulateur(tr.getPath());
		Interface i = new Interface();
		i.saveSimulation(this);
	}
	
	public void load(String pathSimulation)
	{
		Interface i = new Interface();
		Simulateur load = i.loadSimulation(pathSimulation);
	    this.ihm.setHorloge(new Horloge(load));
		this.ihm.refresh();
	}

	public void setIhm(IHM ihm) {
		this.ihm = ihm;
	}
	
	public HashMap<Couple, Integer> getInfosAssignationFeux() {
		
		ArrayList<MapEntite> listeFeuAllume = new ArrayList<MapEntite>();
		
		// On recherche la liste des feux qui sont allum�s
		for(MapEntite mapentite : mapEntites) {
			
			// M�ga crade mais pour l'instant, on laisse pour faire marcher le truc premi�rement (�ventuellement cr�er une Interface du genre "Disparaissable" -pas d'inspiration pour le nom - pour le Feu 
			// ou tout autre catastrophe)
			if(mapentite instanceof Feu && !(((Feu)mapentite).isFeuEteint())) {
				listeFeuAllume.add(mapentite);
			}
		}
		
		// Liste de la forme <Couple, Integer> avec Couple de la forme <Bot, Feu>
		HashMap<Couple, Integer> listSmallestDistanceBotFeu = new HashMap<Couple, Integer>();
		Couple coupleTemp = new Couple();
		
		// Pour chaque robot, on lui demande son chemin le plus cours pour chacun des feux
		for(MapEntite mapentite : mapEntites) {

			// M�ga crade mais pour l'instant, on laisse pour faire marcher le truc premi�rement (�ventuellement cr�er une Interface du genre "D�pla�able" pour les robots => permet de rentre le truc bien extensible
			// si ils veulent faire la simu avec autre chose que des robots
			if(mapentite instanceof Bot) {
				
				
				coupleTemp = ((Bot) mapentite).getSmallestDistanceEntites(this.map, listeFeuAllume); // On r�cup�re le r�sultat sous la forme <Feu, Integer>
				
				
				
				// listSmallestDistanceBotFeu prend un couple de la forme <Bot, Feu> et un Integer.
				// On cr�er le couple en r�cup�rant donc le Bot (mapentite) ainsi que le Feu (coupleTemp.premier)
				
				Couple botFeu = new Couple();
				botFeu.setPremier(mapentite);
				botFeu.setSecond(coupleTemp.getPremier());
				
				
				// On int�gre finalement le couple<Bot, Feu> � listSmallestDistanceBotFeu comme Key et la distance (Integer) comme value
				
				listSmallestDistanceBotFeu.put(botFeu, (Integer)coupleTemp.getSecond());
				
			}
		}
		
		// On pourrait aussi mettre MapEntite en tant qu'Interface, ainsi on pourrait foutre une m�thode "isDisparaissable" permettant d'�tendre le truc � n'importe quelle MapEntite (extensible donc) et de pas avoir
		// � s'occuper de la classe r�elle. Dans la pratique, c'est la m�me chose que laisser MapEntite en classe abstraite mais niveau architecture ou s�mantique, c'est mieux
		// Ou alors le simulateur a tout simplement deux listes : une de feux et une de robots cas il n'y finalement pas beaucoup de points communs entre les deux � part d'�tre sur la map => cr�ation d'une interface
		
		return new HashMap<Couple, Integer>();
	}
}